package org.dding.core.system.handler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.dbcp.BasicDataSource;
import org.dding.core.log.ILogger;
import org.dding.core.log.LoggerFactory;
import org.dding.core.manager.IModuleManager;
import org.dding.core.system.datasource.DataSource;
import org.dding.core.util.ClassUtils;
import org.dding.core.util.StandaloneXmlParser.DataSourceConfig.PoolConfig;

public class DbcpHandler implements DataSourceHadnler {

	private static ILogger logger = LoggerFactory.getLogger(DbcpHandler.class);

	final static Set<String> properties = new HashSet<String>(
			Arrays.asList(new String[] { "initialSize", "maxActive", "maxIdle",
					"maxWait", "removeAbandoned", "removeAbandonedTimeout",
					"minIdle", "minEvictableIdleTimeMillis",
					"numTestsPerEvictionRun" }));

	public DataSource createDataSource(DataSourceConfiguration config) {
		loadModule(config);
		BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName(config.dataSourceConfig.driver);
		ds.setUsername(config.dataSourceConfig.username);
		ds.setPassword(config.dataSourceConfig.password);
		ds.setUrl(config.dataSourceConfig.url);
		PoolConfig poolConfig = config.dataSourceConfig.poolConfig;
		for (String proeperty : properties) {
			try {
				PropertyDescriptor pd = new PropertyDescriptor(proeperty,
						ds.getClass());
				Method wM = pd.getWriteMethod();
				if (wM != null)
					wM.invoke(ds, ClassUtils.newObject(
							wM.getParameterTypes()[0],
							poolConfig.getProperty(proeperty)));
			} catch (Exception e) {
				logger.warn(e, "set property " + proeperty + " failure.");
				continue;
			}
		}

		return new DataSource(ds,config);
	}

	private boolean loadModule(DataSourceConfiguration config) {
		String moduleIdentifer = config.dataSourceConfig.poolConfig.id;
		if (moduleIdentifer != null && !"".equals(moduleIdentifer)) {
			IModuleManager moduleManager = config.moduleManager;
			try {
				moduleManager.loadModule(moduleIdentifer);
			} catch (Throwable e) {
				logger.warn(e, "load module " + moduleIdentifer + " failure.");
				return false;
			}
			return true;
		} else {
			logger.warn("pool id must be exist.");
			return false;
		}
	}

	public boolean closeDataSource(DataSource dataSource) {

		if (dataSource == null) {
			logger.warn("close datasource is null.");
			return false;
		}
		if (dataSource.getDatasource() instanceof BasicDataSource) {
			try {
				BasicDataSource.class.cast(dataSource).close();
			} catch (SQLException e) {
				logger.warn(e, "close datasource failure.");
				return true;
			}
		}
		return true;
	}
}
